package com.github.bryx.workflowweb.config.exception;

import com.github.bryx.workflowweb.config.entity.ResultEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.HttpStatus;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.sql.SQLSyntaxErrorException;
import java.util.stream.Collectors;


@RestControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(value = Exception.class)
    @ResponseStatus(HttpStatus.OK)
    public ResultEntity exception(Exception e){
        return ResultEntity.ofError(e.getMessage());
    }

    @ExceptionHandler(BadSqlGrammarException.class)
    @ResponseStatus(HttpStatus.OK)
    public ResultEntity badSqlGrammarException(BadSqlGrammarException e){
        return ResultEntity.ofError(e.getMessage());
    }

    @ExceptionHandler(SQLSyntaxErrorException.class)
    @ResponseStatus(HttpStatus.OK)
    public ResultEntity sQLSyntaxErrorException(SQLSyntaxErrorException e){
        return ResultEntity.ofError(e.getMessage());
    }

    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseStatus(HttpStatus.OK)
    public ResultEntity handlerBindException(ConstraintViolationException e){
        String errorMsg = e.getConstraintViolations().stream()
                .map(ConstraintViolation::getMessage)
                .collect(Collectors.joining(","));
        return ResultEntity.ofError(errorMsg);
    }

    @ExceptionHandler(value = {RuntimeException.class})
    @ResponseStatus(HttpStatus.OK)
    public ResultEntity runtimeExceptionHandler(RuntimeException e) {
        return ResultEntity.ofError(e.getMessage());
    }

    @ExceptionHandler(value = {SecurityExtception.class})
    @ResponseStatus(HttpStatus.OK)
    public ResultEntity securityExceptionHandler(SecurityExtception e) {
        return ResultEntity.ofError(ResultEntity.RESPONSE_CODE.SECURITY_ERROR, e.getMessage());
    }

    @ExceptionHandler(value = {BusinessException.class})
    @ResponseStatus(HttpStatus.OK)
    public ResultEntity businessExceptionHandler(BusinessException e) {
        return ResultEntity.ofError(e.getMessage());
    }
    @ExceptionHandler(value = {TokenException.class})
    @ResponseStatus(HttpStatus.OK)
    public ResultEntity businessExceptionHandler(TokenException e) {
        return ResultEntity.ofError(ResultEntity.RESPONSE_CODE.SECURITY_ERROR, e.getMessage());
    }

    @ExceptionHandler(value = {MethodArgumentNotValidException.class})
    @ResponseStatus(HttpStatus.OK)
    public ResultEntity methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        String errorMsg = e.getBindingResult().getAllErrors().stream()
                .map(DefaultMessageSourceResolvable::getDefaultMessage)
                .collect(Collectors.joining(","));
        return ResultEntity.ofError(errorMsg);
    }

    @ExceptionHandler(value = {BindException.class})
    @ResponseStatus(HttpStatus.OK)
    public ResultEntity bindExceptionHandler(BindException e) {
        String errorMsg
                = e.getBindingResult()
                .getAllErrors()
                .stream()
                .map(DefaultMessageSourceResolvable::getDefaultMessage)
                .collect(Collectors.joining(","));
        return ResultEntity.ofError(errorMsg);
    }
}
